package com.ruoyi.media.createMp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.amazonaws.util.Md5Utils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dtflys.forest.http.ForestCookie;
import com.dtflys.forest.http.ForestResponse;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.media.forestApi.WechatMpCreateApi;
import com.ruoyi.media.threadConfig.ThreadPoolTaskConfig;
import com.ruoyi.media.utils.WxUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import com.ruoyi.media.createMp.domain.bo.MediaCreateWechatMpBo;
import com.ruoyi.media.createMp.domain.vo.MediaCreateWechatMpVo;
import com.ruoyi.media.createMp.domain.MediaCreateWechatMp;
import com.ruoyi.media.createMp.mapper.MediaCreateWechatMpMapper;
import com.ruoyi.media.createMp.service.IMediaCreateWechatMpService;
import org.springframework.util.DigestUtils;

import java.time.Duration;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 快速创建公众号Service业务层处理
 *
 * @author dqw
 * @date 2023-05-04
 */
@RequiredArgsConstructor
@Service
public class MediaCreateWechatMpServiceImpl extends ServiceImpl<MediaCreateWechatMpMapper,MediaCreateWechatMp> implements IMediaCreateWechatMpService {

    private final MediaCreateWechatMpMapper baseMapper;

    private final WechatMpCreateApi wechatMpCreateApi;

    /**
     * 查询快速创建公众号
     */
    @Override
    public MediaCreateWechatMpVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询快速创建公众号列表
     */
    @Override
    public TableDataInfo<MediaCreateWechatMpVo> queryPageList(MediaCreateWechatMpBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<MediaCreateWechatMp> lqw = buildQueryWrapper(bo);
        Page<MediaCreateWechatMpVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询快速创建公众号列表
     */
    @Override
    public List<MediaCreateWechatMpVo> queryList(MediaCreateWechatMpBo bo) {
        LambdaQueryWrapper<MediaCreateWechatMp> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<MediaCreateWechatMp> buildQueryWrapper(MediaCreateWechatMpBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<MediaCreateWechatMp> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getDeptId() != null, MediaCreateWechatMp::getDeptId, bo.getDeptId());
        lqw.eq(bo.getUserId() != null, MediaCreateWechatMp::getUserId, bo.getUserId());
        lqw.like(StringUtils.isNotBlank(bo.getUsername()), MediaCreateWechatMp::getUsername, bo.getUsername());
        lqw.eq(StringUtils.isNotBlank(bo.getPassword()), MediaCreateWechatMp::getPassword, bo.getPassword());
        lqw.eq(bo.getAccountType() != null, MediaCreateWechatMp::getAccountType, bo.getAccountType());
        lqw.eq(bo.getEnterpriseType() != null, MediaCreateWechatMp::getEnterpriseType, bo.getEnterpriseType());
        lqw.eq(StringUtils.isNotBlank(bo.getBusinessNumber()), MediaCreateWechatMp::getBusinessNumber, bo.getBusinessNumber());
        lqw.like(StringUtils.isNotBlank(bo.getLegalPersonName()), MediaCreateWechatMp::getLegalPersonName, bo.getLegalPersonName());
        lqw.eq(StringUtils.isNotBlank(bo.getLegalPersonIdCard()), MediaCreateWechatMp::getLegalPersonIdCard, bo.getLegalPersonIdCard());
        lqw.like(StringUtils.isNotBlank(bo.getSystemName()), MediaCreateWechatMp::getSystemName, bo.getSystemName());
        lqw.eq(StringUtils.isNotBlank(bo.getSystemIdCard()), MediaCreateWechatMp::getSystemIdCard, bo.getSystemIdCard());
        lqw.eq(StringUtils.isNotBlank(bo.getSystemPhone()), MediaCreateWechatMp::getSystemPhone, bo.getSystemPhone());
        lqw.eq(StringUtils.isNotBlank(bo.getSystemPhoneCaptcha()), MediaCreateWechatMp::getSystemPhoneCaptcha, bo.getSystemPhoneCaptcha());
        lqw.eq(bo.getIsSuccess() != null, MediaCreateWechatMp::getIsSuccess, bo.getIsSuccess());
        return lqw;
    }

    /**
     * 新增快速创建公众号
     */
    @Override
    public Boolean insertByBo(MediaCreateWechatMpBo bo) {
        MediaCreateWechatMp add = BeanUtil.toBean(bo, MediaCreateWechatMp.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改快速创建公众号
     */
    @Override
    public Boolean updateByBo(MediaCreateWechatMpBo bo) {
        MediaCreateWechatMp update = BeanUtil.toBean(bo, MediaCreateWechatMp.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(MediaCreateWechatMp entity){
        //TODO 做一些数据校验,如唯一约束
        LoginUser loginUser =  LoginHelper.getLoginUser();
        entity.setUserId(loginUser.getUserId());
        entity.setDeptId(loginUser.getDeptId());
    }

    /**
     * 批量删除快速创建公众号
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public String createAccount(List<Long> ids) {
        for(Long id :ids){
            MediaCreateWechatMp mediaCreateWechatMp =  getById(id);
            //获取登录cookies
            List<ForestCookie> cookiesList = getLoginMpCookies(mediaCreateWechatMp.getUsername(),mediaCreateWechatMp.getPassword());
            mediaCreateWechatMp.setCookies(JSONObject.toJSONString(cookiesList));

            //保存国家信息
            Map<String,Object> countyParams = new HashMap<>(6);
            countyParams.put("token",null);
            countyParams.put("lang","zh_CN");
            countyParams.put("f","json");
            countyParams.put("ajax",1);
            countyParams.put("random",Math.random());
            countyParams.put("country",1017);
            String countyRes = wechatMpCreateApi.savecountry(countyParams,((forestRequest, forestCookies) -> {
                forestCookies.addAllCookies(cookiesList);
            }));
            System.out.println(countyRes);

            //保存账号类型
            Map<String,Object> accountType = new HashMap<>(7);
            accountType.put("token",null);
            accountType.put("lang","zh_CN");
            accountType.put("f","json");
            accountType.put("ajax",1);
            accountType.put("random",Math.random());
            accountType.put("action","savetype");
            accountType.put("type",mediaCreateWechatMp.getAccountType());
            String accountTypeRes = wechatMpCreateApi.saveRegisterpage(accountType,((forestRequest, forestCookies) -> {
                forestCookies.addAllCookies(cookiesList);
            }));
            //更新数据
            updateById(mediaCreateWechatMp);
        }
        return null;
    }


    /**
     * 登录公众号获取cookies
     * @param userName
     * @param password
     * @return
     */
    public List<ForestCookie> getLoginMpCookies(String userName, String password){
        Map<String,Object> loginParam = new HashMap<>();
        loginParam.put("username",userName);
        loginParam.put("pwd", DigestUtils.md5DigestAsHex(password.getBytes()));
        loginParam.put("imgcode",null);
        loginParam.put("f",null);
        loginParam.put("userlang","zh_CN");
        loginParam.put("redirect_url",null);
        loginParam.put("token",null);
        loginParam.put("lang","zh_CN");
        loginParam.put("ajax",1);
        ForestResponse res = wechatMpCreateApi.accountLogin(loginParam);
        int resCode = JSONObject.parseObject(res.getContent()).getJSONObject("base_resp").getInteger("ret");
        if(resCode  == 200023){
            throw new RuntimeException(StringUtils.format("账号  {}  密码错误，请修改后重试！", userName));
        }else if(resCode == 200008){
            throw new RuntimeException(StringUtils.format("账号  {}  需要验证码登录，请稍后再试！", userName));
        }
        return res.getCookies();
    }


    /**
     * 根据类型获取二维码
     * @return
     */
    public Map<String,Object> getQRCodeImage(Long id,int typeId) throws Exception {
        Map<String,Object> resMap = new HashMap<>();
        MediaCreateWechatMp mediaCreateWechatMp = getById(id);
        List<ForestCookie> forestCookieList =   WxUtils.resetForestCookie(mediaCreateWechatMp.getCookies());
        Map<String,Object> ticketParams = new HashMap<>(13);
        ticketParams.put("token",null);
        ticketParams.put("lang","zh_CN");
        ticketParams.put("f","json");
        ticketParams.put("ajax",1);
        ticketParams.put("random",Math.random());
        ticketParams.put("action","getticket");
        ticketParams.put("size",120);
        ticketParams.put("scene",0);
        ticketParams.put("typeid",typeId);

        //法人信息
        if(typeId == 26){

            ticketParams.put("data","{\"operator_name\":\""+mediaCreateWechatMp.getLegalPersonName()
                +"\",\"operator_id\":\""+mediaCreateWechatMp.getLegalPersonIdCard()+"\"}");
            ticketParams.put("extra","{\"operator_name\":\""+mediaCreateWechatMp.getLegalPersonName()+"\",\"operator_id\":\""+
                mediaCreateWechatMp.getLegalPersonIdCard()+"\"," +
                "\"subject\":\""+mediaCreateWechatMp.getBusinessName()+"\",\"refill\":0,\"service_type\":2,\"is_from_legal_person\":1}");
            ticketParams.put("operator_name",mediaCreateWechatMp.getLegalPersonName());
            ticketParams.put("operator_id",mediaCreateWechatMp.getLegalPersonIdCard());
       //管理员信息
        }else{
            ticketParams.put("data","{\"operator_name\":\""+mediaCreateWechatMp.getSystemName()
                +"\",\"operator_id\":\""+mediaCreateWechatMp.getSystemIdCard()+"\"}");
            ticketParams.put("extra","{\"operator_name\":\""+mediaCreateWechatMp.getSystemName()
                +"\",\"operator_id\":\""+mediaCreateWechatMp.getSystemIdCard()+"\",\"subject\":\""
                +mediaCreateWechatMp.getBusinessName()+"\",\"refill\":0,\"service_type\":2," +
                "\"contractor_type\":1,\"is_legal_person_auth\":1}");
            ticketParams.put("operator_name",mediaCreateWechatMp.getSystemName());
            ticketParams.put("operator_id",mediaCreateWechatMp.getSystemIdCard());
        }



        String getticketRes = wechatMpCreateApi.getticket(ticketParams,((forestRequest, forestCookies) -> {
            forestCookies.addAllCookies(forestCookieList);
        }));
        //获取二维码ticket
        JSONObject ticketJson = JSONObject.parseObject(getticketRes);
        String ticket = ticketJson.getString("qrcheck_ticket");
        //法人ticket
        if(typeId == 26){
            mediaCreateWechatMp.setLegalPersonTicket(ticket);
        //管理员ticket
        }else{
            mediaCreateWechatMp.setSystemTicket(ticket);
        }
        updateById(mediaCreateWechatMp);

        //获取二维码
        ForestResponse qrCodeImage = wechatMpCreateApi.getQRCode(ticket,System.currentTimeMillis(),((forestRequest, forestCookies) -> {
            forestCookies.addAllCookies(forestCookieList);
        }));
        resMap.put("ticket",ticket);
        resMap.put("qrcode",qrCodeImage.getByteArray());
        return resMap;
    }



    /**
     * 根据id批量注册公众号
     * @param ids
     * @return
     */
    @Override
    public void batchCreateMp(List<Long> ids) {
        ThreadPoolTaskConfig threadPoolTaskConfig = new ThreadPoolTaskConfig();
        ThreadPoolTaskExecutor threadPoolTaskExecutor = threadPoolTaskConfig.getAsyncExecutor();
       try{
           for(int i = 0 ; i < ids.size();i++){
               int finalI = i;
               threadPoolTaskExecutor.execute(()->{
                   MediaCreateWechatMp mediaCreateWechatMp = getById(ids.get(finalI));
                   List<ForestCookie> forestCookieList = WxUtils.resetForestCookie(mediaCreateWechatMp.getCookies());

                   //提交资料
                   Map<String,Object> params = new HashMap<>();
                   params.put("token","");
                   params.put("lang","zh_CN");
                   params.put("f","json");
                   params.put("ajax",1);
                   params.put("random",Math.random());
                   params.put("action","enterprise_contractor_set");
                   params.put("contractor_type_name","企业");
                   params.put("is_individual",0);
                   params.put("name",mediaCreateWechatMp.getBusinessName());
                   params.put("credential",mediaCreateWechatMp.getBusinessNumber());
                   params.put("register_type_select",3);
                   params.put("register_type",3);
                   params.put("bank_acct_name",null);
                   params.put("bank_name",null);
                   params.put("bank_acct_num",null);
                   params.put("bank_acct_num_confirm",null);
                   params.put("bank_province",null);
                   params.put("bank_city",null);
                   params.put("legal_person_name",mediaCreateWechatMp.getLegalPersonName());
                   params.put("legal_person_idcard",mediaCreateWechatMp.getLegalPersonIdCard());
                   params.put("legal_person_status",1);
                   params.put("legal_person_ticket",mediaCreateWechatMp.getLegalPersonTicket());
                   params.put("operator_type",1);
                   params.put("operator_name",mediaCreateWechatMp.getSystemName());
                   params.put("operator_idcard",mediaCreateWechatMp.getSystemIdCard());
                   params.put("operator_mobile", "+86" + mediaCreateWechatMp.getSystemPhone());
                   params.put("verify_code",mediaCreateWechatMp.getSystemPhoneCaptcha());
                   params.put("qrcheck_status",mediaCreateWechatMp.getSystemIdCard());
                   params.put("qrcheck_ticket",mediaCreateWechatMp.getSystemTicket());
                   params.put("creator_field",null);
                   params.put("creator_platform_other",null);
                   params.put("creator_platform",null);
                   params.put("creator_nickname",null);
                   params.put("creator_certified_stuff",null);
                   params.put("creator_certified_link",null);
                   String res = wechatMpCreateApi.contractorsubmit(params,((forestRequest, forestCookies) -> {
                       forestCookies.addAllCookies(forestCookieList);
                   }));
                   mediaCreateWechatMp.setSubmitRes(res);

                   //填写简介提交
                   Map<String,Object> regParam =new HashMap<>(15);
                   regParam.put("token",null);
                   regParam.put("lang","zh_CN");
                   regParam.put("f","json");
                   regParam.put("ajax",1);
                   regParam.put("random",Math.random());
                   regParam.put("qrcheck_ticket",mediaCreateWechatMp.getSystemTicket());
                   regParam.put("action","register");
                   regParam.put("serviceType",2);
                   regParam.put("nick_name","角豆豆传媒" + finalI);
                   regParam.put("intro","111111111");
                   regParam.put("city","北区");
                   regParam.put("province","香港");
                   regParam.put("country","中国");
                   regParam.put("invade_check",0);
                   regParam.put("biz_categories","{\"biz_categories\":[]}");
                   String registerRes = wechatMpCreateApi.saveRegisterpage(regParam,((forestRequest, forestCookies) -> {
                       forestCookies.addAllCookies(forestCookieList);
                   }));

                   mediaCreateWechatMp.setRegisterRes(registerRes);
                   System.out.println(registerRes);
                   updateById(mediaCreateWechatMp);
               });
           }
       }catch (Exception e){
           e.printStackTrace();
       }
    }


    /**
     * 多线程提交资料
     * @param ids
     */
    @Override
    public void batchCreateSubmit(List<Long> ids) {
        ThreadPoolTaskConfig threadPoolTaskConfig = new ThreadPoolTaskConfig();
        ThreadPoolTaskExecutor threadPoolTaskExecutor = threadPoolTaskConfig.getAsyncExecutor();
        try {
            for (int i = 0; i < ids.size(); i++) {
                int finalI = i;
                threadPoolTaskExecutor.execute(() -> {
                    MediaCreateWechatMp mediaCreateWechatMp = getById(ids.get(finalI));
                    List<ForestCookie> forestCookieList = WxUtils.resetForestCookie(mediaCreateWechatMp.getCookies());
                    Map<String,Object> params = new HashMap<>();
                    params.put("token","");
                    params.put("lang","zh_CN");
                    params.put("f","json");
                    params.put("ajax",1);
                    params.put("random",Math.random());
                    params.put("action","enterprise_contractor_set");
                    params.put("contractor_type_name","企业");
                    params.put("is_individual",0);
                    params.put("name",mediaCreateWechatMp.getBusinessName());
                    params.put("credential",mediaCreateWechatMp.getBusinessNumber());
                    params.put("register_type_select",3);
                    params.put("register_type",3);
                    params.put("bank_acct_name",null);
                    params.put("bank_name",null);
                    params.put("bank_acct_num",null);
                    params.put("bank_acct_num_confirm",null);
                    params.put("bank_province",null);
                    params.put("bank_city",null);
                    params.put("legal_person_name",mediaCreateWechatMp.getLegalPersonName());
                    params.put("legal_person_idcard",mediaCreateWechatMp.getLegalPersonIdCard());
                    params.put("legal_person_status",1);
                    params.put("legal_person_ticket",mediaCreateWechatMp.getLegalPersonTicket());
                    params.put("operator_type",1);
                    params.put("operator_name",mediaCreateWechatMp.getSystemName());
                    params.put("operator_idcard",mediaCreateWechatMp.getSystemIdCard());
                    params.put("operator_mobile", "+86" + mediaCreateWechatMp.getSystemPhone());
                    params.put("verify_code",mediaCreateWechatMp.getSystemPhoneCaptcha());
                    params.put("qrcheck_status",mediaCreateWechatMp.getSystemIdCard());
                    params.put("qrcheck_ticket",mediaCreateWechatMp.getSystemTicket());
                    params.put("creator_field",null);
                    params.put("creator_platform_other",null);
                    params.put("creator_platform",null);
                    params.put("creator_nickname",null);
                    params.put("creator_certified_stuff",null);
                    params.put("creator_certified_link",null);
                    String res = wechatMpCreateApi.contractorsubmit(params,((forestRequest, forestCookies) -> {
                        forestCookies.addAllCookies(forestCookieList);
                    }));
                    mediaCreateWechatMp.setSubmitRes(res);
                    updateById(mediaCreateWechatMp);
                });
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 每间隔三秒请求一次验证码，超过三分钟销毁线程
     * @return
     */
    public String getVerifiableCode(Long id,String txToken,String phone){
        String chace = ""; //验证码
        //设置一分钟的有效期，避免重复发送
        RedisUtils.setCacheObject("sendPhone-" + id,phone, Duration.ofMinutes(60));
        //调用腾讯接口发送验证码
        MediaCreateWechatMp mediaCreateWechatMp = getById(id);
        List<ForestCookie> forestCookiesList = WxUtils.resetForestCookie(mediaCreateWechatMp.getCookies());

        if(!WxUtils.isNumeric(phone)){
            throw new RuntimeException("不是手机号码！");
        }
        Map<String,Object> params = new HashMap<>(9);
        params.put("token",null);
        params.put("lang","zh_CN");
        params.put("f","json");
        params.put("ajax",1);
        params.put("random",Math.random());
        params.put("form","mobile");
        params.put("action","set");
        params.put("mobile","+86" + phone);
        params.put("register_method",3);
        String sendRes = wechatMpCreateApi.getSystemPhoneCache(params,((forestRequest, forestCookies) -> {
            forestCookies.addAllCookies(forestCookiesList);
        }));
        int resCode = JSONObject.parseObject(sendRes).getJSONObject("base_resp").getInteger("ret");
        System.out.println(sendRes);
        System.out.println(resCode);

        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            int count = 0;
            @Override
            public void run() {
                // 请求第三方接口，获取数据
                String res = wechatMpCreateApi.getPhoneCache(txToken,phone);
                // 判断是否有数据
                System.out.println(res);
                if (res.contains("微信公众平台验证码")) {
                    // 执行相关操作
                    mediaCreateWechatMp.setSystemPhone(phone);
                    String resStr = res.split("\\|")[1]; //获取验证码字符串
                    Pattern pattern = Pattern.compile("\\d+");
                    Matcher matcher = pattern.matcher(resStr);
                    if (matcher.find()) {
                        String code = matcher.group();
                        mediaCreateWechatMp.setSystemPhoneCaptcha(code);
                         updateById(mediaCreateWechatMp);
                    }
                    // 取消定时任务，避免重复执行
                    this.cancel();
                    timer.cancel();
                } else {
                    count++;
                    // 如果3分钟还没有数据，则销毁线程
                    if (count >= 60) {
                        // 执行相关操作
                        // 取消定时任务，避免重复执行
                        this.cancel();
                        timer.cancel();
                    }
                }
            }
        };
        // 定时器每间隔3秒执行一次任务
        timer.schedule(task, 0, 5000);
        return chace;
    }



}
